# PhotoScreen - This screen displays photograph in fullscreen
# Copyright (C) 2007 Lauri Taimila
# 
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
# 
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

__licence__ = "GPLv2"
__copyright__ = "2007, Lauri Taimila"
__author__ = "Lauri Taimila <lauri@taimila.com>"

import gc
import os
import gtk
import clutter

from frontend.user_event import UserEvent
from frontend.gui.screens.screen import Screen
from frontend.gui.transitions.transition import Transition

class PhotoScreen(Screen):
    """
    PhotoScreen
    
    This screen displays photograph in fullscreen. Screen also allows user to 
    zoom in and view photograph information.
    """
    
    # Constants for view
    PHOTO_VIEW = 0
    INFORMATION_VIEW = 1
    
    # How much one zoom click zooms in
    ZOOM_FACTOR = 0.5
    MOVE_SIZE = 100
    
    def __init__(self, ui, frontend, data):
        """
        Initialize screen
        
        @param frontend: FrontendClient object
        @param theme: Theme object
        @param data: List [current photo index, List of Image objects]
        """
        self.group = clutter.Group()
        Screen.__init__(self, ui.STAGE_WIDTH, ui.STAGE_HEIGHT)
        
        self.ui = ui
        self.frontend = frontend
        self.theme = frontend.getTheme()
        self.animate = self.frontend.get_configuration().show_effects()
        
        self.view = self.PHOTO_VIEW             # Current view
        self.zoom_level = 1                     # Current zoom level
        self.index = data[0]                    # Index of the current image
        self.images = data[1]                   # List of image objects
        
        # Create black background
        self.bg = clutter.Rectangle()
        self.bg.set_size(self.ui.STAGE_WIDTH, self.ui.STAGE_HEIGHT)
        self.bg.set_color((0,0,0,255))
        self.bg.show()
        self.group.add(self.bg)
        
        # Screen Title (Displayed at the bottom left corner)
        screen_title = clutter.Label()
        screen_title.set_font_name(self.theme.getFont() + " " + str(self.ui.y(0.13)) + "px")
        screen_title.set_color(self.theme.getColor("screentitle"))
        screen_title.set_text("Information")
        screen_title.set_name("screen_title")
        screen_title.set_position(self.ui.x(0), self.ui.y(0.87))
        screen_title.show()
        self.group.add(screen_title)
        
        self._create_information_view()
        
        self._chage_image(self.index)
        
        self.group.show()
        ui.getStage().add(self.group)

    def set_animate(self, boolean):
        """Animate this screen."""
        self.animate = boolean

    def _create_information_view(self):
        """
        Create actors for information view.
        """
        self.info = clutter.Group()
        
        # Title
        title_h = clutter.Label()
        title_h.set_font_name(self.theme.getFont() + " " + str(self.ui.y(0.0416)) + "px")
        title_h.set_color(self.theme.getColor("subtitle"))
        title_h.set_text("Title:")
        title_h.set_position(0, 0)
        self.info.add(title_h)
        
        title = clutter.Label()
        title.set_font_name(self.theme.getFont() + " " + str(self.ui.y(0.0416)) + "px")
        title.set_color(self.theme.getColor("title"))
        title.set_text(self.images[self.index].get_title())
        title.set_position(self.ui.x(0.1464), 0)
        self.info.add(title)
        
        # Comment
        comment_h = clutter.Label()
        comment_h.set_font_name(self.theme.getFont() + " " + str(self.ui.y(0.0416)) + "px")
        comment_h.set_color(self.theme.getColor("subtitle"))
        comment_h.set_text("Comment:")
        comment_h.set_position(0, self.ui.y(0.0911))
        self.info.add(comment_h)
        
        comment = clutter.Label()
        comment.set_font_name(self.theme.getFont() + " " + str(self.ui.y(0.0416)) + "px")
        comment.set_color(self.theme.getColor("title"))
        comment.set_text(self.images[self.index].get_description())
        comment.set_position(self.ui.x(0.1464), self.ui.y(0.0911))
        self.info.add(comment)
        
        # Album
        album_h = clutter.Label()
        album_h.set_font_name(self.theme.getFont() + " " + str(self.ui.y(0.0416)) + "px")
        album_h.set_color(self.theme.getColor("subtitle"))
        album_h.set_text("Album:")
        album_h.set_position(0, self.ui.y(0.1823))
        self.info.add(album_h)
        
        album = clutter.Label()
        album.set_font_name(self.theme.getFont() + " " + str(self.ui.y(0.0416)) + "px")
        album.set_color(self.theme.getColor("title"))
        album.set_text(self.images[self.index].get_album().get_title())
        album.set_position(self.ui.x(0.1464), self.ui.y(0.1823))
        self.info.add(album)
        
        # Date
        date_h = clutter.Label()
        date_h.set_font_name(self.theme.getFont() + " " + str(self.ui.y(0.0416)) + "px")
        date_h.set_color(self.theme.getColor("subtitle"))
        date_h.set_text("Date:")
        date_h.set_position(0, self.ui.y(0.2709))
        self.info.add(date_h)
        
        date = clutter.Label()
        date.set_font_name(self.theme.getFont() + " " + str(self.ui.y(0.0416)) + "px")
        date.set_color(self.theme.getColor("title"))
        date.set_text(self.images[self.index].get_date())
        date.set_position(self.ui.x(0.1464), self.ui.y(0.2709))
        self.info.add(date)
        
        # Time
        time_h = clutter.Label()
        time_h.set_font_name(self.theme.getFont() + " " + str(self.ui.y(0.0416)) + "px")
        time_h.set_color(self.theme.getColor("subtitle"))
        time_h.set_text("Time:")
        time_h.set_position(0, self.ui.y(0.3646))
        self.info.add(time_h)
        
        time = clutter.Label()
        time.set_font_name(self.theme.getFont() + " " + str(self.ui.y(0.0416)) + "px")
        time.set_color(self.theme.getColor("title"))
        time.set_text(self.images[self.index].get_time()[:5])
        time.set_position(self.ui.x(0.1464), self.ui.y(0.3646))
        self.info.add(time)
        
        # Resolution
        resolution_h = clutter.Label()
        resolution_h.set_font_name(self.theme.getFont() + " " + str(self.ui.y(0.0416)) + "px")
        resolution_h.set_color(self.theme.getColor("subtitle"))
        resolution_h.set_text("Resolution:")
        resolution_h.set_position(0, self.ui.y(0.4557))
        self.info.add(resolution_h)
        
        resolution = clutter.Label()
        resolution.set_font_name(self.theme.getFont() + " " + str(self.ui.y(0.0416)) + "px")
        resolution.set_color(self.theme.getColor("title"))
        resolution.set_text(str(self.images[self.index].get_width()) + "x" + str(self.images[self.index].get_height()))
        resolution.set_position(self.ui.x(0.1464), self.ui.y(0.4557))
        self.info.add(resolution)
        
        # File size
        size_h = clutter.Label()
        size_h.set_font_name(self.theme.getFont() + " " + str(self.ui.y(0.0416)) + "px")
        size_h.set_color(self.theme.getColor("subtitle"))
        size_h.set_text("File size:")
        size_h.set_position(0, self.ui.y(0.5469))
        self.info.add(size_h)
        
        size = clutter.Label()
        size.set_font_name(self.theme.getFont() + " " + str(self.ui.y(0.0416)) + "px")
        size.set_color(self.theme.getColor("title"))
        size.set_text(str(self.images[self.index].get_filesize()))
        size.set_position(self.ui.x(0.1464), self.ui.y(0.5469))
        self.info.add(size)
        
        # Create hashtable for items
        self.info_actors = {}
        self.info_actors['title'] = title
        self.info_actors['comment'] = comment
        self.info_actors['album'] = album
        self.info_actors['date'] = date
        self.info_actors['time'] = time
        self.info_actors['resolution'] = resolution
        self.info_actors['size'] = size
        
        self.info.set_position(self.ui.x(0.0732), self.ui.y(0.1302))
        self.info.set_opacity(0)
        self.info.show_all()
        self.group.add(self.info)
        
    def _update_information_view(self):
        """
        Update actors of the information view to correspond current image.
        """
        image = self.images[self.index]
        self.info_actors['title'].set_text(image.get_title())
        self.info_actors['comment'].set_text(image.get_description())
        self.info_actors['album'].set_text(image.get_album().get_title())
        self.info_actors['date'].set_text(image.get_date())
        self.info_actors['time'].set_text(image.get_time()[:5])
        self.info_actors['resolution'].set_text(str(image.get_width()) + "x" + str(image.get_height()))
        self.info_actors['size'].set_text(str(image.get_filesize()))
        
    def _chage_image(self, index):
        """
        Change current image. Display image from given index.
        """
        try:
            #self.group.remove(self.texture)
            #del self.texture
            self.texture.destroy()
        except AttributeError:
            pass # No previous texture in memory. No problem, let's continue
        
        # Create a new texture and display it
        image = self.images[index]
        self.index = index
        self.texture = clutter.Texture()
        buffer = gtk.gdk.pixbuf_new_from_file(image.get_filename())
        self.texture.set_pixbuf(buffer)
        self._scale_image(self.texture)
        self.texture.show()
        
        if self.view == self.INFORMATION_VIEW:
            self._scale_image(self.texture, 0.6)
            if self.texture.get_width() < self.texture.get_height():
                x = ((self.ui.STAGE_WIDTH / 2 - self.texture.get_width() * self.texture.get_scale()[0]) / 2) + (self.ui.STAGE_WIDTH / 2)
            else:
                x = (self.ui.STAGE_WIDTH / 2) 
            self.texture.set_position(int(x), self.ui.y(0.1302))
        
        self._update_information_view()
        self.group.add(self.texture)
        
    def _scale_image(self, texture, zoom_level=1):
        """
        Scale image. Scaleing doesn't change image aspect ratio.
        @param texture: Texture to scale
        @param zoom_level: Zoom level - Default value is 1 (no zoom)
        """
        #TODO: Zoom feature is not implemented completely! Center position when zoomed
        w = texture.get_width()
        h = texture.get_height()
        x_ratio = self.ui.STAGE_WIDTH / float(w)
        y_ratio = self.ui.STAGE_HEIGHT / float(h)
        
        if x_ratio > y_ratio:
            texture.set_anchor_point_from_gravity(clutter.GRAVITY_CENTER)
            texture.set_scale(self.ui.STAGE_HEIGHT / float(h) * zoom_level, 
                              self.ui.STAGE_HEIGHT / float(h) * zoom_level)
            texture.set_anchor_point(0,0)
            
            if zoom_level == 1: # Center image if in normal size
                new_width = int(w * (self.ui.STAGE_HEIGHT / float(h)))
                new_x = int((self.ui.STAGE_WIDTH - new_width) / float(2))
                texture.set_position(new_x, 0)
        else:
            texture.set_anchor_point_from_gravity(clutter.GRAVITY_CENTER)
            texture.set_scale(self.ui.STAGE_WIDTH / float(w) * zoom_level, 
                              self.ui.STAGE_WIDTH / float(w) * zoom_level)
            texture.set_anchor_point(0,0)
            
            if zoom_level == 1:  # Center image if in normal size
                new_height = int(h * (self.ui.STAGE_WIDTH / float(w)))
                new_y = int((self.ui.STAGE_HEIGHT - new_height) / float(2))
                texture.set_position(0, new_y)

    def _calculate_photograph_coordinates(self):
        """
        Return x position of the photograph. This X-coordinate sets photo
        to the center of the screen in fullscreen mode. This method is used
        when photo is animated from the info view to the fullscreen view.
        """
        w = self.texture.get_width()
        h = self.texture.get_height()
        x_ratio = self.ui.STAGE_WIDTH / float(w)
        y_ratio = self.ui.STAGE_HEIGHT / float(h)
        
        if x_ratio > y_ratio:
            new_width = int(w * (self.ui.STAGE_HEIGHT / float(h)))
            x = int((self.ui.STAGE_WIDTH - new_width) / float(2))
            y = 0
        else:
            new_height = int(h * (self.ui.STAGE_WIDTH / float(w)))
            y = int((self.ui.STAGE_HEIGHT - new_height) / float(2))
            x = 0
        return (x,y)
        
    def _change_to_info_view(self):
        """
        Change from fullscreen photo view to information view
        """
        # Calculate X-coordinate for small photograph
        if self.texture.get_width() < self.texture.get_height():
            x = ((self.ui.STAGE_WIDTH / 2 - self.texture.get_width() * self.texture.get_scale()[0]) / 2) + (self.ui.STAGE_WIDTH / 2)
        else:
            x = (self.ui.STAGE_WIDTH / 2)
        
#        if self.animate:
#            # Fade in information texts and screen title
#            self.info_tl_1 = clutter.Timeline(13, 26)
#            alpha = clutter.Alpha(self.info_tl_1, clutter.ramp_inc_func)
#            behaviour = clutter.BehaviourOpacity(alpha, 0, 255)
#            behaviour.apply(self.screen_title)
#            behaviour.apply(self.info)
#            
#            # Fade out black background
#            self.info_tl_2 = clutter.Timeline(13, 26)
#            alpha = clutter.Alpha(self.info_tl_2, clutter.ramp_inc_func)
#            behaviour = clutter.BehaviourOpacity(alpha, 255, 0)
#            behaviour.apply(self.bg)
#            
#            # Scale and move photograph to right side of the screen
#            self.info_tl_3 = clutter.Timeline(13, 26)
#            alpha = clutter.Alpha(self.info_tl_3, clutter.ramp_inc_func)
#            behaviour = clutter.BehaviourPath(alpha, 
#                                              ((self.texture.get_x(), self.texture.get_y()),
#                                              (x,100)))
#            behaviour = clutter.BehaviourScale(alpha, 
#                                               self.texture.get_scale()[0], 
#                                               self.texture.get_scale()[0] * 0.6)
#            behaviour.apply(self.texture)
#            
#            self.info_tl_1.start()
#            self.info_tl_2.start()
#            self.info_tl_3.start()
#            self.info_tl_4.start()
#        else:
        self.screen_title.show()
        self.bg.set_opacity(0)
        self.info.set_opacity(255)
        self._scale_image(self.texture, 0.6)
        self.texture.set_position(x, self.ui.y(0.1302))            
        
    def _change_to_photo_view(self):
        """
        Change from information view to fullscreen photo view
        """
        #if self.animate:
        # Fade out information texts and screen title
#        self.photo_tl_1 = clutter.Timeline(13, 26)
#        alpha = clutter.Alpha(self.photo_tl_1, clutter.ramp_inc_func)
#        behaviour = clutter.BehaviourOpacity(255, 0, alpha)
#        behaviour.apply(self.screen_title)
#        behaviour.apply(self.info)
#        
#        # Fade in black background
#        self.photo_tl_2 = clutter.Timeline(13, 26)
#        alpha2 = clutter.Alpha(self.photo_tl_2, clutter.ramp_inc_func)
#        behaviour = clutter.BehaviourOpacity(0, 255, alpha2)
#        behaviour.apply(self.bg)
#        
#        # Move photograph to fullscreen
#        self.photo_tl_3 = clutter.Timeline(13, 26)
#        alpha3 = clutter.Alpha(self.photo_tl_3, clutter.ramp_inc_func)
#        behaviour = clutter.BehaviourPath( alpha3, ((self.texture.get_x(), self.texture.get_y()),
#                                          self._calculate_photograph_coordinates())) #FIXME: Calculate corrent position
#        behaviour.apply(self.texture)
#        
#        # Scale photograph to fullscreen
#        self.photo_tl_4 = clutter.Timeline(13, 26)
#        alpha4 = clutter.Alpha(self.photo_tl_4, clutter.ramp_inc_func)
#        behaviour = clutter.BehaviourScale(alpha4, self.texture.get_scale()[0], self.texture.get_scale()[0] / 0.6)
#        behaviour.apply(self.texture)
#        
#        self.photo_tl_1.start()
#        self.photo_tl_2.start()
#        self.photo_tl_3.start()
#        self.photo_tl_4.start()
        #else:
        self.screen_title.hide()
        self.bg.set_opacity(255)
        self.info.set_opacity(0)
        self._scale_image(self.texture)

    def get_group(self):
        """
        Get all actors of the screen.
        @return clutter.Group 
        """
        return self.group

    def get_type(self):
        """Return screen type."""
        return Screen.NORMAL
    
    def get_name(self):
        """Return screen name (human readble)"""
        return "PhotoScreen"
    
    def handle_user_event(self, event):   
        """ 
        Handle screen specific user events
        @param event: UserEvent object
        """
        type = event.get_type()
        
        if type == UserEvent.NAVIGATE_LEFT:
            # Change to previous image
            if self.zoom_level == 1 or self.view == self.INFORMATION_VIEW:
                if self.index == 0:
                    self.index = len(self.images) - 1
                else:
                    self.index = self.index - 1
                self._chage_image(self.index)
            # Change texture position (texture is zoomed)
            else:
                self.texture.move_by(self.MOVE_SIZE, 0)
                
        elif type == UserEvent.NAVIGATE_RIGHT:
            # Change to previous image
            if self.zoom_level == 1  or self.view == self.INFORMATION_VIEW:
                if self.index == len(self.images) - 1:
                    self.index = 0
                else:
                    self.index = self.index + 1
                self._chage_image(self.index)
            # Change texture position (texture is zoomed)
            else:
                self.texture.move_by(-self.MOVE_SIZE, 0)
        
        elif type == UserEvent.NAVIGATE_UP and self.zoom_level != 1:
            self.texture.move_by(0,self.MOVE_SIZE)
            
        elif type == UserEvent.NAVIGATE_DOWN and self.zoom_level != 1:
            self.texture.move_by(0,-self.MOVE_SIZE)
            
        # Zoom image
        elif type == UserEvent.NAVIGATE_SELECT:
            if self.view == self.PHOTO_VIEW:
                if self.zoom_level >= 3:
                    self.zoom_level = 1
                else:
                    self.zoom_level = self.zoom_level + self.ZOOM_FACTOR
                self._scale_image(self.texture, self.zoom_level)
            
        # Switch view (fullscreen photo / information screen)
        elif type == UserEvent.NAVIGATE_CONTENT:
            if self.view == self.PHOTO_VIEW:
                self.view = self.INFORMATION_VIEW
                self._change_to_info_view()
            else:
                self.view = self.PHOTO_VIEW
                self._change_to_photo_view()